#include "ctreemodel.h"
#include "ctreeitem.h"

#include <QDataStream>

#include <QtGui>

#include "constants.h"

CTreeModel::CTreeModel(CDatabase &db, QObject *parent)
    : QAbstractItemModel(parent), m_db(db)
{
    rootItem = createRoot();

    this->setSupportedDragActions(Qt::MoveAction);
}

CTreeModel::~CTreeModel()
{
    delete rootItem;
}

CTreeItem* CTreeModel::createRoot()
{
    return new CTreeItem(m_db, rootId());
}

int CTreeModel::columnCount(const QModelIndex &/*parent*/) const
{
/*    if (parent.isValid())
        return static_cast<CTreeItem*>(parent.internalPointer())->columnCount();
    else
        return rootItem->columnCount();*/
    return 1;
}

QVariant CTreeModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    CTreeItem *item = static_cast<CTreeItem*>(index.internalPointer());

    switch(role)
    {
        case Qt::DisplayRole: return QString("%1 [%2]").arg(item->name().toString()).arg(item->entries());
        case Qt::DecorationRole: return item->icon();
        default: return QVariant();
    }
}

Qt::ItemFlags CTreeModel::flags(const QModelIndex &index) const
{
    Qt::ItemFlags defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;

    if (index.isValid())
        return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
    else
        return Qt::ItemIsDropEnabled | defaultFlags;
}

QVariant CTreeModel::headerData(int, Qt::Orientation, int) const
{
    //if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
      //  return rootItem->data(section);

    return QVariant();
}

QModelIndex CTreeModel::index(int row, int column, const QModelIndex &parent)
            const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    CTreeItem *parentItem;

    if (!parent.isValid())
        parentItem = rootItem;
    else
        parentItem = static_cast<CTreeItem*>(parent.internalPointer());

    CTreeItem *childItem = parentItem->child(row);
    if (childItem)
        return createIndex(row, column, childItem);
    else
        return QModelIndex();
}

QModelIndex CTreeModel::findIndex(QModelIndex idx, QString id)
{
    CTreeItem *item;
    if(!idx.isValid())
    {
        if(rootItem->childCount()==0)
            return QModelIndex();

        item = rootItem;
    }
    else
        item = static_cast<CTreeItem*>(idx.internalPointer());

    for(int i=0; i<item->childCount(); i++)
    {
        CTreeItem *child_item = item->child(i);
        if(child_item->id()==id)
            return index(i, 0, idx);
    }

    for(int i=0; i<item->childCount(); i++)
    {
        QModelIndex child_idx = findIndex(index(i, 0, idx), id);
        if(child_idx.isValid())
            return child_idx;
    }

    return QModelIndex();
}

QModelIndex CTreeModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();

    CTreeItem *childItem = static_cast<CTreeItem*>(index.internalPointer());
    CTreeItem *parentItem = childItem->parent();

    if (parentItem == rootItem)
        return QModelIndex();

    return createIndex(parentItem->row(), 0, parentItem);
}

int CTreeModel::rowCount(const QModelIndex &parent) const
{
    CTreeItem *parentItem;
    if (parent.column() > 0)
        return 0;

    if (!parent.isValid())
    {
        parentItem = rootItem;
    }
    else
    {
        parentItem = static_cast<CTreeItem*>(parent.internalPointer());
    }

    return parentItem->childCount();
}

void CTreeModel::setupModelData(CTreeItem *parent)
{
    QList<QString> children = m_db.getSectionChildern(parent->id());

    foreach(QString i, children)
    {
        debug("Child: " + i);
        CTreeItem *item = new CTreeItem(m_db, i, parent);
        setupModelData(item);
        parent->appendChild(item);
    }
}

QString CTreeModel::itemId(const QModelIndex &parent) const
{
    if(!parent.isValid())
        return QString(32, QChar('0'));

    return static_cast<CTreeItem*>(parent.internalPointer())->id();
}

CTreeItem* CTreeModel::item(const QModelIndex &index)
{
    if(!index.isValid())
        return 0;

    return static_cast<CTreeItem*>(index.internalPointer());
}


void CTreeModel::refill(bool need_update)
{
    if(rootItem)
        delete rootItem;

    rootItem = createRoot();
    setupModelData(rootItem);

    reset();
    if(need_update)
        emit update(false);
}

QString CTreeModel::itemName(const QModelIndex &index) const
{
    if(!index.isValid())
        return QString();

    CTreeItem *item = static_cast<CTreeItem*>(index.internalPointer());
    return item->name().toString();
}

Qt::DropActions CTreeModel::supportedDropActions() const
{
    return Qt::MoveAction;
}

QStringList CTreeModel::mimeTypes() const
{
    QStringList result;
    result << MIME_SECTION;
    result << MIME_ENTRY;
    return result;
}

QMimeData* CTreeModel::mimeData(const QModelIndexList &indexes) const
{
    QMimeData *mimeData = new QMimeData();
    QByteArray encodedData;
    QDataStream in(&encodedData, QIODevice::WriteOnly);

    QModelIndex idx = indexes.at(0);
    CTreeItem *item = static_cast<CTreeItem*>(idx.internalPointer());
    CTreeItem *parent = item->parent();

    in << item->id();
    in << parent->id();

    mimeData->setData(MIME_SECTION, encodedData);

    return mimeData;
}

bool CTreeModel::dropMimeData(const QMimeData *data,
     Qt::DropAction action, int, int column, const QModelIndex &parent)
{
    if (action == Qt::IgnoreAction)
        return true;

    if(column>0)
        return false;

    CTreeItem *newParent;
    if(parent.isValid())
        newParent = static_cast<CTreeItem*>(parent.internalPointer());
    else
        newParent = rootItem;

    if(data->hasFormat(MIME_SECTION))
    {
        QString id;
        QString oldParentId;

        QDataStream out(data->data(MIME_SECTION));
        out >> id;
        out >> oldParentId;

        CTreeItem *oldParent = rootItem->findById(oldParentId);
        if(oldParent==0)
        {
            refill();
            return true;
        }

        moveSection(id, newParent->id());

        refill();

        return true;
    }
    else if(data->hasFormat(MIME_ENTRY))
    {
        if(newParent==rootItem)
            return false;

        QString id;
        QDataStream out(data->data(MIME_ENTRY));
        out >> id;

        debug("Moving entry: " + id);

        moveEntry(id, newParent->id());
        refill(false);
        emit update(true);
        return true;
    }

    return false;
}

void CTreeModel::update(CTreeItem *item)
{
    if(item==0)
    {
        debug("is null");
        return;
    }

    CTreeItem *parent = item->parent();
    if(parent==0)
        parent = rootItem;

    QString id = item->id();
    parent->deleteChild(item);
    delete item;

    item = new CTreeItem(m_db, id, parent);
    setupModelData(item);

    parent->appendChild(item);
}

void CTreeModel::moveSection(QString id, QString parent)
{
    QMap<QString, QVariant> values;
    values.insert("parent", parent);

    m_db.updateSection(values, id);

//    m_model->refill();
}

void CTreeModel::moveEntry(QString id, QString parent)
{
    QMap<QString, QVariant> values;
    values.insert("parent", parent);

    m_db.updateEntry(values, id);
}
